package com.simga.library.base;

import android.content.Intent;
import android.os.Looper;

import androidx.appcompat.app.AppCompatActivity;

import com.google.gson.JsonParseException;
import com.simga.library.http.APIException;
import com.simga.library.http.IRequestResult;
import com.simga.library.utils.HawkKey;
import com.simga.library.utils.LogUtil;
import com.trello.rxlifecycle2.android.ActivityEvent;
import com.trello.rxlifecycle2.android.FragmentEvent;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
import com.trello.rxlifecycle2.components.support.RxFragment;

import org.json.JSONException;

import java.io.IOException;
import java.net.ConnectException;
import java.text.ParseException;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import retrofit2.adapter.rxjava2.HttpException;


public abstract class IPresenter implements IRequestResult {

    public IView mView;
    private IModel mModel;
    //对应HTTP的状态码
    private static final int UNAUTHORIZED = 401;
    private static final int FORBIDDEN = 403;
    private static final int NOT_FOUND = 404;
    private static final int REQUEST_TIMEOUT = 408;
    private static final int INTERNAL_SERVER_ERROR = 500;
    private static final int BAD_GATEWAY = 502;
    private static final int SERVICE_UNAVAILABLE = 503;
    private static final int GATEWAY_TIMEOUT = 504;

    public IModel getModel() {
        if (mModel == null)
            mModel = new IModel();
        return mModel;
    }
    public void bindView(IView mView) {
        this.mView = mView;
    }

    /**
     * 数据请求
     */
    protected <T> void request(int postCode, Observable<T> request, Object data) {
        if (mView instanceof RxAppCompatActivity)
            requestA((RxAppCompatActivity) mView, postCode, getObservable(mView, request), data);
        else
            requestF((RxFragment) mView, postCode, getObservable(mView, request), data);
    }

    protected <T> void requestA(RxAppCompatActivity a, int postCode, Observable<T> request, Object data) {
        request2(a, postCode, getObservable(a, request), data);
    }
    protected <T> void requestF(RxFragment f, int postCode, Observable<T> request, Object data) {
        request2((AppCompatActivity) f.getActivity(), postCode, getObservable(f, request), data);
    }
    protected <T> void request2(final AppCompatActivity a, final int postCode, final Observable<T> request, final Object data) {
        getModel().request(request, new Consumer<Disposable>() {
            @Override
            public void accept(final Disposable d) throws Exception {
                if (Looper.myLooper() == Looper.getMainLooper())
                    IPresenter.this.doOnSubscribe(postCode, data, d);
                else
                    a.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            doOnSubscribe(postCode, data, d);
                        }
                    });
            }
        }, new Observer<T>() {
            @Override
            public void onSubscribe(Disposable d) {
            }
            @Override
            public void onNext(final T t) {
                mView.dimissProLoading();
                if (!a.getSupportFragmentManager().isDestroyed()) {
                    if (Looper.myLooper() == Looper.getMainLooper())
                        IPresenter.this.onNext(postCode, t, data);
                    else
                    a.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            IPresenter.this.onNext(postCode, t, data);
                        }
                    });
                }
            }

            @Override
            public void onError(final Throwable e) {
                mView.dimissProLoading();
                if (!a.getSupportFragmentManager().isDestroyed()) {
                    if (Looper.myLooper() == Looper.getMainLooper())
                        IPresenter.this.analyError(postCode, data, e);
                    else
                        a.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                IPresenter.this.onError(postCode, data, e);
                            }
                        });
                }
            }
            @Override
            public void onComplete() {
                mView.dimissProLoading();
                if (!a.getSupportFragmentManager().isDestroyed()) {
                    if (Looper.myLooper() == Looper.getMainLooper())
                        IPresenter.this.onCompleted(postCode, data);
                    else
                        a.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                IPresenter.this.onCompleted(postCode, data);
                            }
                        });
                }
            }
        });
    }

    protected <T> Observable<T> getObservable(Object any, Observable<T> request) {
        if (any instanceof RxAppCompatActivity)
            return request.compose(((RxAppCompatActivity) any).<T>bindUntilEvent(ActivityEvent.DESTROY));
        else if (any instanceof RxFragment)
            return request.compose(((RxFragment) any).<T>bindUntilEvent(FragmentEvent.DESTROY));
        return request;
    }
    @Override
    public void doOnSubscribe(int postCode, Object data, Disposable disposable) {}
    @Override
    public <T> void onNext(int postCode, T result, Object data) {}
    private void analyError(int postCode, Object data, Throwable e) {
        try {
            if (e instanceof HttpException) {        //HTTP请求异常
                onHttpException(postCode, data, e);
            } else if (e instanceof IOException) {        //网络超时
                onIOException(postCode, data, e);
            } else if (e instanceof JsonParseException
                    || e instanceof JSONException
                    || e instanceof ParseException) {//数据异常
                onJsonParseException(postCode, data, e);
            } else if (e instanceof ConnectException) {//链接异常
                onConnectException(postCode, data, e);
            } else if (((APIException) e).isLoginExpired()) {//登录失效的错误信息
                onLoginException();
            } else if (((APIException) e).getCode().equals("1015")) {//后台返回的错误信息
                onNext(postCode, null, data);
            } else {
                otherException(postCode, data, (APIException) e);
            }
        }catch (Exception e1){
            if(e1.getMessage().contains("null cannot be cast to non-null")){
                onNext(postCode, null, data);
            }
            mView.showErrorMessage(postCode, "-200", e1.getMessage());
        }
    }

    @Override
    public void onConnectException(int postCode, Object data, Throwable e) {
        mView.showErrorMessage(-10086, "-10086", "网络链接异常");
    }
    @Override
    public void onJsonParseException(int postCode, Object data, Throwable e) {
        mView.showErrorMessage(-10086, "-10086", "数据解析异常");
    }
    @Override
    public void onError(int postCode, Object data, Throwable e) {}
    @Override
    public void onLoginException() {
            mView.showErrorMessage(1000, "5000102", "登录信息已过期,请重新登录");
            if (mView instanceof RxAppCompatActivity) {
                ((RxAppCompatActivity) mView).sendBroadcast(new Intent(HawkKey.USER_LOGIN_OUT));
            } else {
                ((RxFragment) mView).getActivity().sendBroadcast(new Intent(HawkKey.USER_LOGIN_OUT));
            }
    }

    @Override
    public void onHttpException(int postCode, Object data, Throwable e) {
        HttpException httpException = (HttpException) e;
        switch (httpException.code()) {
            case UNAUTHORIZED:
            case FORBIDDEN:
            case NOT_FOUND:
            case REQUEST_TIMEOUT:
            case GATEWAY_TIMEOUT:
            case INTERNAL_SERVER_ERROR:
            case BAD_GATEWAY:
            case SERVICE_UNAVAILABLE:
            default:
                LogUtil.e(LogUtil.TAG, e.getMessage());
                mView.showErrorMessage(-10086, "-10086", "网络异常");
                break;
        }
    }
    @Override
    public void onIOException(int postCode, Object data, Throwable e) {
        LogUtil.e(LogUtil.TAG, e.getMessage());
        mView.showErrorMessage(-10086, "-10086", "网络异常");
    }

    @Override
    public void otherException(int postCode, Object data, APIException e) {
    }
    @Override
    public void onCompleted(int postCode, Object data) {
    }
}
